<template>
  <q-page class="q-pa-md">
    <q-btn class="float-right" color="primary" icon="arrow_back" outline title="返回" to="/" />
    <div class="q-pb-md text-h5">出库QC</div>
    <!--错误提示-->
    <q-banner class="text-white bg-red q-mb-md" dense inline-actions v-if="serverErrorMessage">
      {{ serverErrorMessage }}
      <template v-slot:action>
        <q-btn @click="serverErrorMessage = ''" dense flat icon="close" size="sm" />
      </template>
    </q-banner>
    <div class="row q-pt-sm q-col-gutter-sm">
      <div class="col-12 row">
        <div style="line-height: 28px" class="col-4">
          <q-checkbox v-model="$d.isVLot" label="外部批号" dense @update:model-value="onChangedVLot" />
        </div>
        <div class="col-8">
          <easy-input v-model="$d.caseId" ref="caseId" autofocus @focus="fx.ui.select"
            @keyup.enter="getPackForQc" placeholder="箱号(Case ID)"></easy-input>
        </div>
      </div>
      <div class="col-6">
        <q-btn color="primary" label="重置" @click="onReset" style="width: 100%" :disable="$d.loadingCaseIdState" />
      </div>
      <div class="col-6">
        <q-btn color="primary" label="完成QC" @click="onDoneQc" v-if="fx.hasModifyRight('Wms.Work.Order.PackQc')"
          :disable="!$d.form.caseId || ('35' <= $d.form.packState)" style="width: 100%" :loading="$d.doneQcSubmitingState" />
      </div>
    </div>
    <div class="row q-mt-sm q-col-gutter-sm">
      <div class="row q-col-gutter-sm col-12">
        <div class="col-6">
          <span>仓库</span>
          <easy-input v-model="$d.form.whName" readonly></easy-input>
        </div>
        <div class="col-6">
          <span>货主</span>
          <easy-input v-model="$d.form.storerAbbrName" readonly></easy-input>
        </div>
        <div class="col-6">
          <span>状态</span>
          <q-input :hide-bottom-space="true" readonly dense maxlength="40" outlined square stack-label
            :model-value="fx.fmt.fmtPackState($d.form.packState)" :input-class="notNeedQcStateClass"></q-input>
        </div>
        <div class="col-6">
          <span>毛重(kg)</span>
          <q-input :hide-bottom-space="true" readonly dense maxlength="40" outlined square stack-label
            :model-value="$d.form.gw" :input-class="gwOrCubeClass($d.form.gw)"></q-input>
        </div>
        <div class="col-6">
          <span>体积(m³)</span>
          <q-input :hide-bottom-space="true" readonly dense maxlength="40" outlined square stack-label
            :model-value="$d.form.cube" :input-class="gwOrCubeClass($d.form.cube)"></q-input>
        </div>
        <div class="col-12">
          <span>仓库作业备注</span>
          <q-input :hide-bottom-space="true" readonly autogrow dense maxlength="300" outlined square stack-label
            type="textarea" :model-value="$d.form.workRemark"></q-input>
        </div>
        <div class="col-12">
          <span>描述</span>
          <q-input :hide-bottom-space="true" readonly autogrow dense maxlength="300" outlined square stack-label
            type="textarea" :model-value="$d.form.descriptions"></q-input>
        </div>
        <div class="col-6">
          <span>品牌</span>
          <simple-filter-select :options="$d.brandDropdownList" :readonly="!$d.form.caseId"
            :use-filter="false" option-label="brandName" option-value="brandId" v-model="$d.brandId"
            :auto-select-single-option="$d.allInFlag && ($d.brandDropdownList.length === 1)"
            :trigger-auto-sel-every-ops-chg="true" @update:model-value="brandIdChanged" />
        </div>
        <div class="col-6">
          <span>解码规则</span>
          <simple-filter-select :options="$d.wmBrandDecodeRuleLite" :readonly="!$d.form.caseId"
            :use-filter="false" option-label="brandDecodeRuleName" option-value="brandDecodeRuleId" v-model="$d.brandDecodeRuleId"
            :auto-select-single-option="$d.allInFlag && ($d.wmBrandDecodeRuleLite.length === 1)"
            :trigger-auto-sel-every-ops-chg="true" />
        </div>
        <div class="col-6">
          <span>2D</span>
          <div class="bg-grey-3">
            <q-checkbox class="full-width q-pa-xs" color="primary q-pa-xs" dense
              v-model="$d.is2DEnabled" @update:model-value="onChanged2D" />
          </div>
        </div>

        <div class="col-6">
          <span>原厂二维码扫描</span>
          <easy-input v-model="$d.scanContent" ref="scanContent"
            :readonly="(!$d.form.caseId) || (!$d.is2DEnabled) || (!$d.brandDecodeRuleId) || $d.brandBarcodeDecodingState"
            @keyup.enter="brandBarcodeDecode" :loading="$d.brandBarcodeDecodingState" />
        </div>

        <div class="col-12">
          <span>料号/原厂料号</span>
          <easy-input v-model="$d.skuForQc" @focus="fx.ui.select" ref="skuInputField" :readonly="!$d.form.caseId"
            @update:model-value="onSkuInputFieldChanged" @keyup.enter="onSkuEntered"/>
        </div>

        <div class="col-12" v-show="$d.isVLot">
          <span>外部批号</span>
          <easy-input v-model="$d.vLot" @focus="fx.ui.select" ref="vLot" :readonly="($d.currentLineIdxForQc < 0) || !$d.isVLot"
            @keyup.enter="onVLotEntered"/>
        </div>

        <div class="col-6">
          <span>数量</span>
          <easy-input v-model="$d.qtyForQc" ref="qtyInputField" @keyup.enter="confirmLine"
            :readonly="$d.currentLineIdxForQc<0 || $d.onePiece || !$d.vLotCheck" />
        </div>
        <div class="col-6">
          <span>单件包装</span>
          <div class="bg-grey-3">
            <q-checkbox class="full-width q-pa-xs" color="primary q-pa-xs" dense v-model="$d.onePiece"
              :disable="!$d.form.caseId" @update:model-value="onChangedOnePiece" />
          </div>
        </div>
      </div>
    </div>
    <q-table :columns="$d.isVLot ? $d.columnsInfoQcForVLot : $d.columnsInfoQc" :rows="$d.form.lines" :hide-pagination="true" :loading="$d.loadingCaseIdState"
      v-model:pagination="$d.paginationInfoQc" binary-state-sort color="primary" dense flat hide-selected-banner
      row-key="mfSku" separator="cell" class="simple-border q-mt-md">
      <!--状态-->
      <template v-slot:body-cell-state="props">
        <q-td :props="props">
          <span :class="(props.row.qty - props.row.scanedQty) === 0 ? 'text-green' : (props.row.scanedQty - props.row.qty) > 0 ? 'text-red' : 'text-black'">
            {{(props.row.qty - props.row.scanedQty) === 0 ? '完成' : (props.row.qty - props.row.scanedQty) > 0 ? '未完成' : 0 > (props.row.qty - props.row.scanedQty) ? '超出' : ''}}
          </span>
        </q-td>
      </template>
      <!--无数据提示-->
      <template v-slot:no-data>
        <div class="full-width items-center justify-center row">
          <q-icon name="error_outline" />
          无数据
        </div>
      </template>
    </q-table>
  </q-page>
</template>
<script lang="ts">
export default {
  name: 'QcStd'
}
</script>
<script lang="ts" setup>
import {computed, nextTick, reactive, ref} from 'vue'
import {QInput} from 'quasar'
import useVuelidate from '@vuelidate/core'
import {playBeepSound, playErrorSound, playSuccessSound} from '@njt/wms/helper/audio'
import _ from 'lodash'
import {WmPackForQc, WmPackLineForQc} from '@njt/wms/defs/work/qc'
import {DecodableBrandInfo} from '@njt/wms/defs/basic/brand'
import {WmBrandLite, WmBrandDecodeRuleLite} from '../../defs/asnReceive'

const caseId = ref<QInput | null>(null)
const scanContent = ref<QInput | null>(null)
const skuInputField = ref<QInput | null>(null)
const qtyInputField = ref<QInput | null>(null)
const vLot = ref<QInput | null>(null)
let serverErrorMessage = ref('')

let $d = reactive({
  brandDecodeRuleId: null as number | null,
  wmBrandDecodeRuleLite: [] as WmBrandDecodeRuleLite[],
  // 是否启用外部批号
  isVLot: true,
  // 箱号
  caseId: null as string | null,
  // QC操作信息
  qcOperationInfos: [] as Record<string, string | number | null | Date>[],
  // 表单数据
  form: {
    caseId: null,
    packState: null,
    lines: [] as WmPackLineForQc[]
  } as WmPackForQc,
  // 待QC的料号
  skuForQc: null as string | null,
  // 待QC的数量
  qtyForQc: null as number | null,
  // 单件包装
  onePiece: false,
  // 获取装箱信息状态
  loadingCaseIdState: false,
  // 是否所有的品牌都存在解码规则
  allInFlag: false,
  // 品牌下拉
  brandDropdownList: [] as WmBrandLite[],
  // 启用二维码扫描
  is2DEnabled: true,
  // 外部批号
  vLot: null as string | null,
  // 外部批号检查
  vLotCheck: false,
  // 原厂二维码
  scanContent: null,
  // 品牌ID
  brandId: null,
  // 完成QC状态
  doneQcSubmitingState: false,
  // 原厂二维码状态
  brandBarcodeDecodingState: false,
  // 当前要做QC的行, 在sku输入框按enter，查找，找到就确定这行，>=0表示有选中的行，否则表示没有
  currentLineIdxForQc: -1,
  // 列参数
  columnsInfoQcForVLot: [
    {
      label: '料号',
      name: 'sku',
      field: 'sku',
      align: 'left'
    },
    {
      label: '数量',
      name: 'qty',
      field: 'qty',
      align: 'left'
    },
    {
      label: '扫描数量',
      name: 'scanedQty',
      field: 'scanedQty',
      align: 'left'
    },
    {
      label: '状态',
      name: 'state',
      field: 'state',
      align: 'left'
    },
    {
      label: '外部批号',
      name: 'vLot',
      field: 'vLot',
      align: 'left'
    }
  ],
  columnsInfoQc: [
    {
      label: '料号',
      name: 'sku',
      field: 'sku',
      align: 'left'
    },
    {
      label: '数量',
      name: 'qty',
      field: 'qty',
      align: 'left'
    },
    {
      label: '扫描数量',
      name: 'scanedQty',
      field: 'scanedQty',
      align: 'left'
    },
    {
      label: '状态',
      name: 'state',
      field: 'state',
      align: 'left'
    }
  ],
  // 分页参数
  paginationInfoQc: {
    // 页码
    page: 1,
    // 每页多少条
    rowsPerPage: 0
  },
})

const rules = {

}

const v$ = useVuelidate(rules,computed(() => $d.form), {$autoDirty: true})

// 获取装箱信息
const getPackForQc = () => {
  serverErrorMessage.value = ''
  $d.qcOperationInfos = []
  v$.value.$reset()
  if ($d.caseId) {
    if ($d.caseId.length < 12) {
      $d.caseId = _.padStart($d.caseId, 12, '0')
    }
    $d.skuForQc = null
    $d.qtyForQc = $d.onePiece ? 1 : null
    $d.loadingCaseIdState = true
    let errFlag = false
    $d.caseId = $d.caseId.trim()
    let workState = 1
    $f.axios.get<WmPackForQc>('/wms/work/order/get-pack-for-qc?caseId=' + $d.caseId + '&vLot=' + $d.isVLot)
      .then((resp) =>{
        $d.form = resp.data
        _.forEach($d.form.lines, (v) => {
          v.scanedQty = 0
        })
        workState = 2
        return $f.axios.get<DecodableBrandInfo>('/wms/basic/brand/get-decodable-brands-of-pack/' + resp.data.packId)
      })
      .then((resp) => {
        if (resp) {
          $d.allInFlag = resp.data.allInFlag
          $d.brandDropdownList = resp.data.brandInfos
        }
      })
      .catch((err) =>{
        playErrorSound()
        if (err.response?.status === 404  && workState === 1) {
          serverErrorMessage.value = '箱号不存在'
        } else if (workState === 1) {
          serverErrorMessage.value = $f.getAxiosErrMsg(err)
        } else if (workState === 2) {
          $f.ui.showNotifyFailed($f.getAxiosErrMsg(err))
        }
        errFlag = true
      })
      .finally(() =>{
        $d.loadingCaseIdState = false
        if (errFlag) {
          void nextTick(() => {
            caseId.value && caseId.value.focus()
          })
        } else {
          if ($d.is2DEnabled && $d.allInFlag && ($d.brandDropdownList.length === 1)) {
            void nextTick(() => {
              scanContent.value && scanContent.value.focus()
            })
          } else {
            void nextTick(() => {
              skuInputField.value && skuInputField.value.focus()
            })
          }
        }
      })
  } else {
    playErrorSound()
    serverErrorMessage.value = '必须指定箱号'
  }
}

// vLot变动
const onChangedVLot = (val: string) => {
  if (!val) {
    $d.vLot = null
    $d.vLotCheck = false
  }
  if ($d.caseId) {
    getPackForQc()
  }
  window.localStorage.setItem('wms:qc:is-vLot', val)
  void nextTick(() => {
    caseId.value && caseId.value.focus()
  })
}

// 重置
const onReset = () => {
  if ($d.onePiece) {
    $d.qtyForQc = 1
  } else {
    $d.qtyForQc = null
  }
  $d.brandDecodeRuleId = null
  $d.wmBrandDecodeRuleLite = []
  $d.vLot = null
  $d.allInFlag = false
  $d.scanContent = null
  $d.brandId = null
  $d.brandDropdownList = []
  serverErrorMessage.value = ''
  $d.qcOperationInfos = []
  $d.form = {
    lines: [] as WmPackLineForQc[]
  } as WmPackForQc
  $d.skuForQc = null
  void nextTick(() => {
    caseId.value && caseId.value.focus()
  })
}

// 完成QC
const onDoneQc = () => {
  serverErrorMessage.value = ''
  let qcOkay = _.every($d.form.lines, (v) => {
    return v.qty === v.scanedQty
  })
  if (qcOkay) {
    let params = {
      caseId: $d.form.caseId,
      qcType: 'System',
      qcBtnDt: new Date(),
      qcOperationInfos: $d.qcOperationInfos
    }
    $d.doneQcSubmitingState = true
    $f.axios
      .post('/wms/work/order/done-qc', params)
      .then(() => {
        onReset()
        $f.ui.showNotifySucceeded('QC成功')
        $d.caseId = null
        playSuccessSound()
      })
      .catch((err) => {
        playErrorSound()
        serverErrorMessage.value = $f.getAxiosErrMsg(err)
      })
      .finally(() => {
        $d.doneQcSubmitingState = false
      })
  } else {
    playErrorSound()
    serverErrorMessage.value = '数量不正确,请检查'
  }
}

// 不需要QC的状态显示样式
let notNeedQcStateClass = computed(() => {
  return {
    'text-bold': true,
    'text-positive': String($d.form.packState) >= '35'
  }
})

const gwOrCubeClass = (value: number) => {
  if (value === 0) {
    return {
      'text-bold': true,
      'text-red': true
    }
  }
}

const onChanged2D = (val: boolean) => {
  window.localStorage.setItem('pda:qc:is-2d-checked', String(val))
  // 光标聚焦判断
  if ($d.is2DEnabled && $d.brandDecodeRuleId) {
    void nextTick(() => {
      scanContent.value && scanContent.value.focus()
    })
  } else {
    void nextTick(() => {
      skuInputField.value && skuInputField.value.focus()
    })
  }
}

// 品牌解码
const brandBarcodeDecode = () => {
  serverErrorMessage.value = ''
  if ($d.brandDecodeRuleId && $d.scanContent) {
    let params = {
      brandDecodeRuleId: $d.brandDecodeRuleId,
      scanContent: $d.scanContent
    }
    $d.brandBarcodeDecodingState = true
    $f.axios.post('/wms/basic/brand/brand-barcode-decode', params)
      .then((resp) => {
        $d.skuForQc = resp.data.sku
        $d.qtyForQc = resp.data.qty
        if ($d.isVLot) {
          $d.vLot = resp.data.vLot
        }
        if ($d.skuForQc) {
          onSkuEntered()
        }
      })
      .catch((err) => {
        playErrorSound()
        serverErrorMessage.value = $f.getAxiosErrMsg(err)
      })
      .finally(() => {
        $d.brandBarcodeDecodingState = false
      })
  }
}

// 回车原厂料号/料号
const onSkuEntered = () => {
  serverErrorMessage.value = ''
  $d.vLotCheck = false
  if ($d.skuForQc) {
    $d.skuForQc = $d.skuForQc.trim()
    $d.currentLineIdxForQc = _.findIndex(
      $d.form.lines,
      (v) => _.toUpper(v.mfSku as string).indexOf(_.toUpper($d.skuForQc as string)) > -1 || _.toUpper($d.skuForQc as string) === _.toUpper(v.sku as string)
    )
    if ($d.currentLineIdxForQc >= 0) {

      if ($d.isVLot) {
        void nextTick(() => {
          void nextTick(() => {
            vLot.value && vLot.value.focus()
          })
        })
      } else {
        $d.vLotCheck = true
        if ($d.onePiece) {
          confirmLine()
          void nextTick(() => {
            skuInputField.value && skuInputField.value.focus()
          })
        } else {
          void nextTick(() => {
            qtyInputField.value && qtyInputField.value.focus()
          })
        }
      }

    } else {
      playErrorSound()
      serverErrorMessage.value = '请检查并输入正确料号'
      void nextTick(() => {
        skuInputField.value && skuInputField.value.blur()
      })
    }
  }
}

let canDoneQc = computed(() => {
  return _.every($d.form.lines, (v) => {
    return v.qty === v.scanedQty
  })
})

// 确认料号
const confirmLine = () => {
  serverErrorMessage.value = ''
  if ($d.currentLineIdxForQc < 0) {
    playErrorSound()
    console.warn('此时currentLineIdxForQc不应该<0，请检查代码')
    return
  }
  let qty = parseInt(String($d.qtyForQc))
  if (qty && qty > 0 && qty <= 100000000) {
    ($d.form.lines[$d.currentLineIdxForQc].scanedQty as number) += qty
    // 记录qc日志
    $d.qcOperationInfos.push({
      sku: $d.skuForQc,
      qty: qty,
      operateDt: new Date()
    })

    // 判断是否需要获取焦点
    let focusFlag = true
    // 确认完成后状态判断
    if ($d.form.lines[$d.currentLineIdxForQc].qty - ($d.form.lines[$d.currentLineIdxForQc].scanedQty as number) < 0) {
      playErrorSound()
      focusFlag = false
    } else if ($d.form.lines[$d.currentLineIdxForQc].qty - ($d.form.lines[$d.currentLineIdxForQc].scanedQty as number) > 0) {
      playBeepSound()
    } else if ($d.form.lines[$d.currentLineIdxForQc].qty - ($d.form.lines[$d.currentLineIdxForQc].scanedQty as number) === 0) {
      if (canDoneQc.value) {
        onDoneQc()
        return
      } else {
        playBeepSound()
      }
    }

    $d.form.lines.unshift($d.form.lines.splice($d.currentLineIdxForQc, 1)[0])
    $d.currentLineIdxForQc = -1
    $d.skuForQc = null
    $d.vLot = null
    if (!$d.onePiece) {
      $d.qtyForQc = null
    }
    v$.value.$reset()
    if ($d.is2DEnabled && !!$d.brandId) {
      $d.scanContent = null
      void nextTick(() => {
        if (focusFlag) {
          scanContent.value && scanContent.value.focus()
        }
      })
    } else {
      void nextTick(() => {
        if (focusFlag) {
          skuInputField.value && skuInputField.value.focus()
        }
      })
    }
    playBeepSound()
  } else {
    playErrorSound()
    serverErrorMessage.value = '请输入正确的数量'
  }
}

const onSkuInputFieldChanged = () => {
  $d.currentLineIdxForQc = -1
}
// 回车外部批号
const onVLotEntered = () => {
  serverErrorMessage.value = ''
  if ($d.vLot) {
    $d.vLot = $d.vLot.trim()
  }
  if (($d.vLot === $d.form.lines[$d.currentLineIdxForQc].vLot) || (!$d.vLot && !$d.form.lines[$d.currentLineIdxForQc].vLot) ) {
    $d.vLotCheck = true
    if ($d.onePiece) {
      confirmLine()
    } else {
      void nextTick(() => {
        qtyInputField.value && qtyInputField.value.focus()
      })
    }
  } else {
    $d.vLotCheck = false
    playErrorSound()
    serverErrorMessage.value = '请检查并输入正确外部批号'
    void nextTick(() => {
      vLot.value && vLot.value.focus()
    })
  }
}

// 单件包装更改
const onChangedOnePiece = (value: boolean) => {
  if (value) {
    $d.qtyForQc = 1
  } else {
    // $d.qtyForQc = null
  }
  window.localStorage.setItem('pdf:qc:one-piece-option', $d.onePiece.toString())
}

const brandIdChanged = (value: number) => {
  if (value) {
    $f.axios.get<WmBrandDecodeRuleLite[]>('/wms/basic/brand/get-brand-decode-rule-simple-list-by-brand-id/' + value)
      .then((resp) => {
        $d.wmBrandDecodeRuleLite = resp.data
      })
      .catch((err) => {
        $f.ui.showNotifyFailed($f.getAxiosErrMsg(err))
      })
  } else {
    $d.wmBrandDecodeRuleLite = []
    $d.brandDecodeRuleId = null
  }
}

const fx = $f
</script>
